// Copyright (c) 2008 Matthew Johnson
// Licensed under the MIT License (see license.txt)
package actionml.animation {
	import actionml.Global;
	class PropertyTweenRenderer extends RendererBase {
		protected var _tween:Tween;
		public function get tween():Tween { return _tween; }
		protected var _property:String;
		protected var _start:Object;
		protected var _end:Object;
		protected var _renderStart:Number;
		protected var _renderDistance:Number;
		protected var _rendering:Boolean;
		public static function isApplicable(targetClass:Class, property:String) {
			return true;
		}
		public function PropertyTweenRenderer(target:Object, property:String, start:Object=null, end:Object=null, tween:Tween=null) {
			var t:Object = PropertyTweenRenderer["getTracer"]({method:"PropertyTweenRenderer", context: "arg"});
			if (!target) {
				t.warn("A target was not provided.  This is ok if a proxy will supply the target during rendering but is an error otherwise." +
					"  The values were target:", target, ", property:", property, ", start:", start, ", end:", end, ", \ntween:", tween);
			}
			if (!property || !tween) {
				t.warn("An expected argument was not provided." +
					"  The values were target:", target, ", property:", property, ", start:", start, ", end:", end, ", \ntween:", tween);
			}
			_tween = tween;
			_target = target;
			_property = property;
			_start = start;
			_end = end;
		}
		public override function get name():String {
			return _property;
		}
		public override function get rendering():Boolean {
			return _rendering;
		}
		public override function prepareToRender() {
			super.prepareToRender();
			var current:Number = _target[_property] || 0;
			var start:Number;
			var end:Number;
			if (_tween && _tween.shouldPlayBackwards) {
				start = this.getValueOrDefault(_end, current);
				end = this.getValueOrDefault(_start, current);
			} else {
				start = this.getValueOrDefault(_start, current);
				end = this.getValueOrDefault(_end, current);
			}
			if (!(current >= start && current <= end
				|| current <= start && current >= end) || _tween && _tween.shouldPlayFromStart) {
				_target[_property] = start;
				current = start;
			}
			_renderStart = current;
			_renderDistance = end - current;
			_rendering = true;
			var t:Object = PropertyTweenRenderer["getTracer"]({method:"prepareToRender", context: "ivars"});
			t.info("prepared to render with values _target:", _target, "_property:", _property, "_renderStart:", _renderStart, ", _renderDistance:", _renderDistance, "_tween:", _tween);
		}
		private function getValueOrDefault(v:Object, d:Number):Number {
			if (!(v is Number)) {
				v = _target["evaluateExpression"](v);
				if (!(v is Number) || isNaN(Number(v))) {
					return d;
				} else {
					return Number(v);
				}
			} else if (isNaN(Number(v))) {
				return d;
			} else {
				return Number(v);
			}
		}
		public override function render(rc:RenderContext) {	
			if (rc.time < _tween.endTime) {
				this.renderFrame(rc);
				// TODO dispatch sync notification
			} else {
				this.renderLastFrame(rc); 
				this.sendEvent(new RenderEvent(RenderEvent.COMPLETE_RENDERING, this));
				_rendering = false;
			}
		}
		internal function renderFrame(rc:RenderContext) {
			_target[_property] = _tween.ease(rc.time - _tween.startTime, _renderStart, _renderDistance, _tween.renderDuration);
		}
		internal function renderLastFrame(rc:RenderContext) {
			_target[_property] = _renderStart + _renderDistance; 
		}
	}
}
